package schoolmath.web.components.content;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Form;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import schoolmath.web.entities.UserGroup;
import schoolmath.web.entities.UserGroupUnit;
import schoolmath.web.services.UserService;
import schoolmath.web.services.valueEncoders.UserGroupEncoder;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@RequiresRoles(value = {"Администратор", "Преподаватель"}, logical = Logical.OR)
public class ManageUserGroupsContent {

	private static Logger logger = LoggerFactory.getLogger(ManageUserGroupsContent.class);
	private List<UserGroup> userGroups;
	private UserGroup userGroup;
	@Inject
	private Session session;
	@Component
	private Form userGroupsEdit;
	@Component
	private Zone userGroupsEditZone;
	private List<UserGroup> deletedUserGroups = new ArrayList<>();
	private boolean inFormSubmission;
	private List<UserGroup> userGroupsSubmitted;
	@Inject
	private UserService userService;
	@Property
	@Inject
	private UserGroupEncoder userGroupEncoder;
	private boolean editing;
	@InjectComponent
	private Zone rowZone;
	@InjectComponent
	private ManageUserGroupUnitsContent manageUserGroupUnitsContent;

	public boolean getCreating() {
		return this.userGroup.getId() == null;
	}

	public boolean getChanging() {
		return editing || this.userGroup.getId() == null;
	}

	public String getChangingId() {
		if (editing) {
			return userGroup.getId().toString();
		} else {
			return "";
		}
	}

	public String getUserCount() {
		if (userGroup.getId() != null) {
			return "" + userGroup.getUserGroupUnitsCount();
		} else {
			return "";
		}
	}

	public UserGroup getUserGroup() {
		return this.userGroup;
	}

	public void setUserGroup(UserGroup userGroup) {
		this.userGroup = userGroup;

		if (inFormSubmission) {
			userGroupsSubmitted.add(userGroup);
		}
	}

	public void onActivate() {
		inFormSubmission = false;
	}

	public UserGroup onAddRow() {
		return new UserGroup("", userService.getUser());
	}

	public void onRemoveRow(UserGroup unitGroup) {
		deletedUserGroups.add(unitGroup);
	}

	@SuppressWarnings("unchecked")
	public List<UserGroup> getUserGroups() {
		if (userGroups == null) {
			userGroups = session.createCriteria(UserGroup.class)
					.add(Restrictions.eq("owner", userService.getUser()))
					.addOrder(org.hibernate.criterion.Order.asc("id")).list();
		}
		return userGroups;
	}

	@CommitAfter
	private void delete() {
		for (UserGroup userGroup : deletedUserGroups) {
			if (userGroup.getId() != null) {
				for (UserGroupUnit userGroupUnit : userGroup.getUserGroupUnits()) {
					session.delete(userGroupUnit);
				}
				session.delete(userGroup);
			}
		}
	}

	@CommitAfter
	private void save() {
		for (UserGroup userGroup : userGroupsSubmitted) {
			if (userGroup.getId() != null) {
				session.update(userGroup);
			} else {
				session.merge(userGroup);
			}
		}
	}

	public void onPrepareForSubmit() {
		inFormSubmission = true;
		userGroupsSubmitted = new ArrayList<>();
	}

	public void onValidateFromUserGroupsEdit() {
		Set<String> names = new HashSet<>();
		for (UserGroup userGroup : userGroupsSubmitted) {
			if (names.contains(userGroup.getName())) {
				userGroupsEdit.recordError("Имеются повторяющиеся названия групп");
				return;
			}
			names.add(userGroup.getName());
		}
	}

	public Object onSuccess() {
		delete();
		save();
		userGroups = null;
		return userGroupsEditZone.getBody();
	}

	public Object onFailure() {
		userGroups = new ArrayList<>(userGroupsSubmitted);
		return userGroupsEditZone.getBody();
	}

	public Object onRefresh() {
		userGroupsEdit.clearErrors();
		userGroups = null;
		return userGroupsEditZone.getBody();
	}

	public Object onEdit(UserGroup userGroup) {
		this.userGroup = userGroup;
		editing = true;
		return rowZone.getBody();
	}

	public Object onCancel(UserGroup userGroup) {
		this.userGroup = userGroup;
		return rowZone.getBody();
	}

	public Object onRefreshPage() {
		return this;
	}

	public Object onEditUnits(UserGroup userGroup) {
		manageUserGroupUnitsContent.setUserGroup(userGroup);
		return manageUserGroupUnitsContent;
	}

}
